package com.hrhx.springboot.util;
import java.math.BigDecimal;
import java.util.ArrayList;

import com.hrhx.springboot.domain.DataPoint;

public class MonadicRegressionLine // implements Evaluatable  
{  
    /** sum of x */  
    private double sumX;  
  
    /** sum of y */  
    private double sumY;  
  
    /** sum of x*x */  
    private double sumXX;  
  
    /** sum of x*y */  
    private double sumXY;  
  
    /** sum of y*y */  
    private double sumYY;  
  
    /** sum of yi-y */  
    private double sumDeltaY;  
  
    /** sum of sumDeltaY^2 */  
    private double sumDeltaY2;  
  
    /** 误差 */  
    private double sse;  
  
    private double sst;  
  
    private double E;  
  
    private String[] xy;  
  
    private ArrayList listX;  
  
    private ArrayList listY;  
  
    private int XMin, XMax, YMin, YMax;  
  
    /** line coefficient a0 */  
    private float a0;  
  
    /** line coefficient a1 */  
    private float a1;  
  
    /** number of data points */  
    private int pn;  
  
    /** true if coefficients valid */  
    private boolean coefsValid;
    
    private String printLine;
  
    /** 
     * Constructor. 
     */  
    public MonadicRegressionLine() {  
        XMax = 0;  
        YMax = 0;  
        pn = 0;  
        xy = new String[2];  
        listX = new ArrayList();  
        listY = new ArrayList();  
    }  
  
    /** 
     * Constructor. 
     *  
     * @param data 
     *            the array of data points 
     */  
    public MonadicRegressionLine(DataPoint data[]) {  
        pn = 0;  
        xy = new String[2];  
        listX = new ArrayList();  
        listY = new ArrayList();  
        for (int i = 0; i < data.length; ++i) {  
            addDataPoint(data[i]);  
        }  
    }  
  
    /** 
     * Return the current number of data points. 
     *  
     * @return the count 
     */  
    public int getDataPointCount() {  
        return pn;  
    }  
  
    /** 
     * Return the coefficient a0. 
     *  
     * @return the value of a0 
     */  
    public float getA0() {  
        validateCoefficients();  
        return a0;  
    }  
  
    /** 
     * Return the coefficient a1. 
     *  
     * @return the value of a1 
     */  
    public float getA1() {  
        validateCoefficients();  
        return a1;  
    }  
  
    /** 
     * Return the sum of the x values. 
     *  
     * @return the sum 
     */  
    public double getSumX() {  
        return sumX;  
    }  
  
    /** 
     * Return the sum of the y values. 
     *  
     * @return the sum 
     */  
    public double getSumY() {  
        return sumY;  
    }  
  
    /** 
     * Return the sum of the x*x values. 
     *  
     * @return the sum 
     */  
    public double getSumXX() {  
        return sumXX;  
    }  
  
    /** 
     * Return the sum of the x*y values. 
     *  
     * @return the sum 
     */  
    public double getSumXY() {  
        return sumXY;  
    }  
  
    public double getSumYY() {  
        return sumYY;  
    }  
  
    public int getXMin() {  
        return XMin;  
    }  
  
    public int getXMax() {  
        return XMax;  
    }  
  
    public int getYMin() {  
        return YMin;  
    }  
  
    public int getYMax() {  
        return YMax;  
    }  
  
    /** 
     * Add a new data point: Update the sums. 
     *  
     * @param dataPoint 
     *            the new data point 
     */  
    public void addDataPoint(DataPoint dataPoint) {  
        sumX += dataPoint.x;  
        sumY += dataPoint.y;  
        sumXX += dataPoint.x * dataPoint.x;  
        sumXY += dataPoint.x * dataPoint.y;  
        sumYY += dataPoint.y * dataPoint.y;  
  
        if (dataPoint.x > XMax) {  
            XMax = (int) dataPoint.x;  
        }  
        if (dataPoint.y > YMax) {  
            YMax = (int) dataPoint.y;  
        }  
  
        // 把每个点的具体坐标存入ArrayList中，备用  
  
        xy[0] = (int) dataPoint.x + "";  
        xy[1] = (int) dataPoint.y + "";  
        if (dataPoint.x != 0 && dataPoint.y != 0) {  
            System.out.print(xy[0] + ",");  
            System.out.println(xy[1]);  
  
            try {  
                // System.out.println("n:"+n);  
                listX.add(pn, xy[0]);  
                listY.add(pn, xy[1]);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
  
            /* 
             * System.out.println("N:" + n); System.out.println("ArrayList 
             * listX:"+ listX.get(n)); System.out.println("ArrayList listY:"+ 
             * listY.get(n)); 
             */  
        }  
        ++pn;  
        coefsValid = false;  
    }  
  
    /** 
     * Return the value of the regression line function at x. (Implementation of 
     * Evaluatable.) 
     *  
     * @param x 
     *            the value of x 
     * @return the value of the function at x 
     */  
    public float at(int x) {  
        if (pn < 2)  
            return Float.NaN;  
  
        validateCoefficients();  
        return a0 + a1 * x;  
    }  
  
    /** 
     * Reset. 
     */  
    public void reset() {  
        pn = 0;  
        sumX = sumY = sumXX = sumXY = 0;  
        coefsValid = false;  
    }  
  
    /** 
     * Validate the coefficients. 计算方程系数 y=ax+b 中的a 
     */  
    private void validateCoefficients() {  
        if (coefsValid)  
            return;  
  
        if (pn >= 2) {  
            float xBar = (float) sumX / pn;  
            float yBar = (float) sumY / pn;  
  
            a1 = (float) ((pn * sumXY - sumX * sumY) / (pn * sumXX - sumX  
                    * sumX));  
            a0 = (float) (yBar - a1 * xBar);  
        } else {  
            a0 = a1 = Float.NaN;  
        }  
  
        coefsValid = true;  
    }  
  
    /** 
     * 返回误差 
     */  
    public double getR() {  
        // 遍历这个list并计算分母  
        for (int i = 0; i < pn - 1; i++) {  
            float Yi = (float) Integer.parseInt(listY.get(i).toString());  
            float Y = at(Integer.parseInt(listX.get(i).toString()));  
            float deltaY = Yi - Y;  
            float deltaY2 = deltaY * deltaY;  
            /* 
             * System.out.println("Yi:" + Yi); System.out.println("Y:" + Y); 
             * System.out.println("deltaY:" + deltaY); 
             * System.out.println("deltaY2:" + deltaY2); 
             */  
  
            sumDeltaY2 += deltaY2;  
            // System.out.println("sumDeltaY2:" + sumDeltaY2);  
  
        }  
  
        sst = sumYY - (sumY * sumY) / pn;  
        // System.out.println("sst:" + sst);  
        E = 1 - sumDeltaY2 / sst;  
  
        return round(E, 4);  
    }  
  
    // 用于实现精确的四舍五入  
    public double round(double v, int scale) {  
  
        if (scale < 0) {  
            throw new IllegalArgumentException(  
                    "The scale must be a positive integer or zero");  
        }  
  
        BigDecimal b = new BigDecimal(Double.toString(v));  
        BigDecimal one = new BigDecimal("1");  
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();  
  
    }  
  
    public float round(float v, int scale) {  
  
        if (scale < 0) {  
            throw new IllegalArgumentException(  
                    "The scale must be a positive integer or zero");  
        }  
  
        BigDecimal b = new BigDecimal(Double.toString(v));  
        BigDecimal one = new BigDecimal("1");  
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).floatValue();  
  
    }  
    
    public String getPrintLine() {
		return "y = " + this.a1 + "x + " + this.a0;
	}

	/**
	 * 多元线性回归分析
	 * 
	 * @param x[m][n]
	 *            每一列存放m个自变量的观察值
	 * @param y[n]
	 *            存放随即变量y的n个观察值
	 * @param m
	 *            自变量的个数
	 * @param n
	 *            观察数据的组数
	 * @param a
	 *            返回回归系数a0,...,am
	 * @param dt[4]
	 *            dt[0]偏差平方和q,dt[1] 平均标准偏差s dt[2]返回复相关系数r dt[3]返回回归平方和u
	 * @param v[m]
	 *            返回m个自变量的偏相关系数
	 */
	public static void sqt2(double[][] x, double[] y, int m, int n, double[] a,
			double[] dt, double[] v) {
		int i, j, k, mm;
		double q, e, u, p, yy, s, r, pp;
		double[] b = new double[(m + 1) * (m + 1)];
		mm = m + 1;
		b[mm * mm - 1] = n;
		for (j = 0; j <= m - 1; j++) {
			p = 0.0;
			for (i = 0; i <= n - 1; i++)
				p = p + x[j][i];
			b[m * mm + j] = p;
			b[j * mm + m] = p;
		}
		for (i = 0; i <= m - 1; i++)
			for (j = i; j <= m - 1; j++) {
				p = 0.0;
				for (k = 0; k <= n - 1; k++)
					p = p + x[i][k] * x[j][k];
				b[j * mm + i] = p;
				b[i * mm + j] = p;
			}
		a[m] = 0.0;
		for (i = 0; i <= n - 1; i++)
			a[m] = a[m] + y[i];
		for (i = 0; i <= m - 1; i++) {
			a[i] = 0.0;
			for (j = 0; j <= n - 1; j++)
				a[i] = a[i] + x[i][j] * y[j];
		}
		chlk(b, mm, 1, a);
		yy = 0.0;
		for (i = 0; i <= n - 1; i++)
			yy = yy + y[i] / n;
		q = 0.0;
		e = 0.0;
		u = 0.0;
		for (i = 0; i <= n - 1; i++) {
			p = a[m];
			for (j = 0; j <= m - 1; j++)
				p = p + a[j] * x[j][i];
			q = q + (y[i] - p) * (y[i] - p);
			e = e + (y[i] - yy) * (y[i] - yy);
			u = u + (yy - p) * (yy - p);
		}
		s = Math.sqrt(q / n);
		r = Math.sqrt(1.0 - q / e);
		for (j = 0; j <= m - 1; j++) {
			p = 0.0;
			for (i = 0; i <= n - 1; i++) {
				pp = a[m];
				for (k = 0; k <= m - 1; k++)
					if (k != j)
						pp = pp + a[k] * x[k][i];
				p = p + (y[i] - pp) * (y[i] - pp);
			}
			v[j] = Math.sqrt(1.0 - q / p);
		}
		dt[0] = q;
		dt[1] = s;
		dt[2] = r;
		dt[3] = u;
	}

	private static int chlk(double[] a, int n, int m, double[] d) {
		int i, j, k, u, v;
		if ((a[0] + 1.0 == 1.0) || (a[0] < 0.0)) {
			System.out.println("fail\n");
			return (-2);
		}
		a[0] = Math.sqrt(a[0]);
		for (j = 1; j <= n - 1; j++)
			a[j] = a[j] / a[0];
		for (i = 1; i <= n - 1; i++) {
			u = i * n + i;
			for (j = 1; j <= i; j++) {
				v = (j - 1) * n + i;
				a[u] = a[u] - a[v] * a[v];
			}
			if ((a[u] + 1.0 == 1.0) || (a[u] < 0.0)) {
				System.out.println("fail\n");
				return (-2);
			}
			a[u] = Math.sqrt(a[u]);
			if (i != (n - 1)) {
				for (j = i + 1; j <= n - 1; j++) {
					v = i * n + j;
					for (k = 1; k <= i; k++)
						a[v] = a[v] - a[(k - 1) * n + i] * a[(k - 1) * n + j];
					a[v] = a[v] / a[u];
				}
			}
		}
		for (j = 0; j <= m - 1; j++) {
			d[j] = d[j] / a[0];
			for (i = 1; i <= n - 1; i++) {
				u = i * n + i;
				v = i * m + j;
				for (k = 1; k <= i; k++)
					d[v] = d[v] - a[(k - 1) * n + i] * d[(k - 1) * m + j];
				d[v] = d[v] / a[u];
			}
		}
		for (j = 0; j <= m - 1; j++) {
			u = (n - 1) * m + j;
			d[u] = d[u] / a[n * n - 1];
			for (k = n - 1; k >= 1; k--) {
				u = (k - 1) * m + j;
				for (i = k; i <= n - 1; i++) {
					v = (k - 1) * n + i;
					d[u] = d[u] - a[v] * d[i * m + j];
				}
				v = (k - 1) * n + k - 1;
				d[u] = d[u] / a[v];
			}
		}
		return (2);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		/**
		 * 一元回归
		 */
		// int i;
		// double[] dt=new double[6];
		// double[] a=new double[2];
		// double[] x={ 0.0,0.1,0.2,0.3,0.4,0.5,
		// 0.6,0.7,0.8,0.9,1.0};
		// double[] y={ 2.75,2.84,2.965,3.01,3.20,
		// 3.25,3.38,3.43,3.55,3.66,3.74};
		// SPT.SPT1(x,y,11,a,dt);
		// System.out.println("");
		// System.out.println("a="+a[1]+" b="+a[0]);
		// System.out.println("q="+dt[0]+" s="+dt[1]+" p="+dt[2]);
		// System.out.println(" umax="+dt[3]+" umin="+dt[4]+" u="+dt[5]);
		/**
		 * 多元回归
		 */
		int i;
		double[] a = new double[4];
		double[] v = new double[3];
		double[] dt = new double[4];

		double[][] x = { { 1.1, 1.0, 1.2, 1.1, 0.9 },
				{ 2.0, 2.0, 1.8, 1.9, 2.1 }, { 3.2, 3.2, 3.0, 2.9, 2.9 } };
		double[] y = { 10.1, 10.2, 10.0, 10.1, 10.0 };
		sqt2(x, y, 3, 5, a, dt, v);
		for (i = 0; i <= 3; i++)
			System.out.println("a(" + i + ")=" + a[i]);
		System.out.println("q=" + dt[0] + "  s=" + dt[1] + "  r=" + dt[2]);
		for (i = 0; i <= 2; i++)
			System.out.println("v(" + i + ")=" + v[i]);
		System.out.println("u=" + dt[3]);

	}

   
}